package com.cib.icarus.core.enums;

import com.cib.icarus.core.utils.ByteUtils;
import com.cib.icarus.core.utils.internals.StrUtils;
import com.google.common.io.BaseEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @author goomba
 */
public enum IcarusHMACHashEnum {

    HMAC_MD5("HmacMD5", 128),
    HMAC_SHA1("HmacSHA1", 160),
    HMAC_SHA224("HmacSHA224", 224),
    HMAC_SHA256("HmacSHA256", 256),
    HMAC_SHA384("HmacSHA384", 384),
    HMAC_SHA512("HmacSHA512", 512),

    ;

    private static final Logger logger = LoggerFactory.getLogger(IcarusHMACHashEnum.class);

    private final String algorithm;

    private final Integer bitLength;

    IcarusHMACHashEnum(String algorithm, Integer bitLength) {
        this.algorithm = algorithm;
        this.bitLength = bitLength;
    }


    public String hashHexStr(String target, String accessKeySecret) {
        if (StrUtils.isBlank(target)) {
            return target;
        }

        byte[] hmacBytes = handler(target, accessKeySecret, algorithm);
        return ByteUtils.arrayToHexString(hmacBytes);
    }

    public Integer hashHexStrLength() {
        return bitLength / 8 * 2;
    }

    public String hashBase64Str(String target, String accessKeySecret) {
        if (StrUtils.isBlank(target)) {
            return target;
        }

        byte[] hmacBytes = handler(target, accessKeySecret, algorithm);
        return BaseEncoding.base64().encode(hmacBytes);
    }

    public Integer hashBase64StrLength() {
        int charLength = bitLength / 8;
        charLength = charLength % 3 == 0 ? charLength : (charLength + (3 - charLength % 3));
        return charLength / 3 * 4;
    }


    private byte[] handler(String target, String accessKeySecret, String algorithm) {
        try {
            Mac instance = Mac.getInstance(algorithm);
            SecretKeySpec secretKeySpec = new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), algorithm);
            instance.init(secretKeySpec);
            return instance.doFinal(target.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException e) {
            // 记录日志
            logger.error("Error in {} signing: {}", algorithm, e.getMessage(), e);
            // 如果算法不支持，则抛出异常
            throw new IllegalArgumentException("Algorithm not found", e);
        } catch (InvalidKeyException e) {
            // 记录日志
            logger.error("Error in {} signing: {}", algorithm, e.getMessage(), e);
            // 如果密钥无效，则抛出异常
            throw new IllegalArgumentException("Invalid key", e);
        }
    }

}
